package com.smartEdu.module.thrift.common;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.apache.thrift.TException;
import org.apache.thrift.TServiceClient;
import org.apache.thrift.async.TAsyncClientManager;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TMultiplexedProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TNonblockingSocket;
import org.apache.thrift.transport.TNonblockingTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;

import com.smartEdu.commons.LogCvt;
import com.smartEdu.module.thrift.client.helloworld.HelloWorldCallback;
import com.smartEdu.module.thrift.server.helloworld.HelloWorldService;

public class ThriftClient {
	private String host;
	private int port;
	private int socketTimeout;
	private int connectTimeout;
//	private TAsyncClientManager clientManager;
	ThreadLocal<TTransport> localSocket = new ThreadLocal<TTransport>();
	ThreadLocal<TCompactProtocol> localProtocol = new ThreadLocal<TCompactProtocol>();
	ThreadLocal<Map<String, TMultiplexedProtocol>> protocolMap= new ThreadLocal<Map<String, TMultiplexedProtocol>>() {;
		public Map<String, TMultiplexedProtocol> initialValue() {  
	        return new HashMap<String, TMultiplexedProtocol>();  
	    }  
	};
	
	public static class TClientParam {
		public String host;
		public int port;
		public int socketTimeout;
		public int connectTimeout;
	}
	
//	public ThriftClient(String host, int port, int socketTimeout, int connectTimeout) {
//		this.host = host;
//		this.port = port;
//		this.socketTimeout = socketTimeout;
//		this.connectTimeout = connectTimeout;
//	}
	
	/**
	 * 初始化异步客户端
	 * @throws TException
	 */
	@SuppressWarnings("unused")
	private void initAsync() throws TException {
		try {
            TAsyncClientManager clientManager = new TAsyncClientManager();
            TNonblockingTransport transport = new TNonblockingSocket(host, port, connectTimeout);
//            TCompactProtocol protocol = new TCompactProtocol(transport);
            HelloWorldService.AsyncClient asyncClient = new HelloWorldService.AsyncClient(new TCompactProtocol.Factory(), clientManager, transport);
            HelloWorldCallback callBack = new HelloWorldCallback();
            asyncClient.sayHello("larry", callBack);
            while (true) {
                Thread.sleep(1);
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
	}
	
	/**
	 * 初始化同步客户端
	 * @throws TException
	 */
	private void initSync() throws TException {
		TSocket baseTransport = new TSocket(host, port, socketTimeout, connectTimeout);
        // 创建传输对象，非阻塞式
        TTransport transport = new TFramedTransport.Factory().getTransport(baseTransport);
		localSocket.set(transport);
		localProtocol.set(new TCompactProtocol(transport));
	}
	
//	public <T> T sendOnetime(List<ThriftClientModel> request) throws TException {
//		TSocket transport = initSync();
//		TCompactProtocol protocol = new TCompactProtocol(transport);
//		for (ThriftClientModel dto : request) {
//			try {
//				Method method = dto.getCls().getMethod(
//						dto.getMethmod(), dto.getDto().getClass());
//				method.invoke(obj, args)
//			} catch (NoSuchMethodException | SecurityException e) {
//				e.printStackTrace();
//			}
//		}
//		TMultiplexedProtocol tmp = new TMultiplexedProtocol(protocol,"TopicService");
//		transport.open();
//		transport.close();
//		return (T) new Object();
//	}
	
	/**
	 * 获取同步客户端
	 * @param cls
	 */
	@SuppressWarnings("unchecked")
	public <T extends TServiceClient> T getSyncClient(Class<T> cls) {
		try {
			confirmThreadLocalSocket();
			String serviceName = cls.getDeclaringClass().getSimpleName();
			System.err.println(serviceName);
			TMultiplexedProtocol tmp;
			if (protocolMap.get().containsKey(serviceName)) {
				tmp = protocolMap.get().get(serviceName);
			} else {
				tmp = new TMultiplexedProtocol(localProtocol.get(), serviceName);
				protocolMap.get().put(serviceName, tmp);
			}
			Constructor<?> c = cls.getConstructor(TProtocol.class);
			LogCvt.info("获取ThriftClient成功");
			return (T) c.newInstance(tmp);
		} catch (TException | NoSuchMethodException | SecurityException 
				| InstantiationException | IllegalAccessException 
				| IllegalArgumentException | InvocationTargetException e) {
			LogCvt.error("获取ThriftClient失败",e);
		}
		return null;
	}
	
	private void confirmThreadLocalSocket() throws TException {
		if (localSocket.get() == null) {
			initSync();
		}
	}
	
	/**
	 * 开启socket通信通道
	 * 后于getClient调用先于service业务函数调用
	 * @throws TTransportException
	 */
	public void open() throws TTransportException {
		if (localSocket.get() != null) {
			localSocket.get().open();
		}
	}
	
	/**
	 * 有调用getClient的线程必须执行
	 * 关闭socket通信通道
	 */
	public void close() {
		if (localSocket.get() != null) {
			localSocket.get().close();
		}
	}
	
	/**
	 * 初始化client的连接参数
	 * @param host
	 * @param port
	 * @param socketTimeout
	 * @param connectTimeout
	 */
	public void initParams(TClientParam param) {
		this.host = param.host;
		this.port = param.port;
		this.socketTimeout = param.socketTimeout;
		this.connectTimeout = param.connectTimeout;
	}
}
